package com.chungkui.check.expression;

import com.chungkui.check.core.Constants;
import com.chungkui.check.expression.decorator.impl.ConditionExpressionDecorator;
import com.chungkui.check.expression.decorator.impl.InsideExpressionDecorator;
import com.chungkui.check.expression.impl.*;
import com.google.common.collect.Maps;
import com.googlecode.aviator.AviatorEvaluator;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;

/**
 * @Author: jason
 * @Date: 2019/12/27 16:17
 * @Version 1.0
 */
public class ExpressionFactory {
    private static Map<String, Class> expressionClassMap = Maps.newConcurrentMap();
    private static final Logger log = LoggerFactory.getLogger(ExpressionFactory.class);

    private ExpressionFactory() {
    }

    static {
        try {
            AviatorEvaluator.addStaticFunctions("str", StringUtils.class);
        } catch (IllegalAccessException | NoSuchMethodException e) {
            log.error("ExpressionFactory init error", e);
        }
        expressionClassMap.put(Constants.DATATYPR_ARRAY, ArrayExpression.class);
        expressionClassMap.put("avt", AviatorExpression.class);
        expressionClassMap.put("double", DoubleExpression.class);
        expressionClassMap.put("in", InExpression.class);
        expressionClassMap.put("int", IntExpression.class);
        expressionClassMap.put(Constants.DATATYPR_JSONARRAY, JsonArrayExpression.class);
        expressionClassMap.put(Constants.DATATYPR_JSON_OBJECT, JsonExpression.class);
        expressionClassMap.put("long", LongExpression.class);
        expressionClassMap.put("notNull", NotNullExpression.class);
        expressionClassMap.put("require", RequireExpression.class);
        expressionClassMap.put("reg", RegExpression.class);
        expressionClassMap.put("date", DateExpression.class);
        expressionClassMap.put("dateInterval", DateIntervalMatchExpression.class);


    }

    public static void registerExpression(String type, Class clazz) {
        if (!MatchExpression.class.isAssignableFrom(clazz)) {
            throw new IllegalArgumentException("clazz must implement  com.chungkui.check.expression.MatchExpression");
        }
        expressionClassMap.put(type, clazz);
    }

    /**
     * 构造表达式对象
     *
     * @param config 校验配置
     * @return MatchExpression 返回构造后的表达式
     */
    public static MatchExpression buildExpression(Map<String, Object> config) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        if (MapUtils.isEmpty(config)) {
            throw new IllegalArgumentException("config can't be null,check your json format");
        } else {
            String type = MapUtils.getString(config, "type");
            MatchExpression matchExpression = null;
            if (StringUtils.isNotEmpty(type)) {
                Class clazz = expressionClassMap.get(type);
                if (clazz == null) {
                    throw new IllegalArgumentException("type:" + type + " not support");
                }
                if (MatchExpression.class.isAssignableFrom(clazz)) {
                    matchExpression = (MatchExpression) clazz.getDeclaredConstructor().newInstance();
                } else {
                    throw new IllegalArgumentException("clazz must implement com.chungkui.check.expression.MatchExpression");
                }
            } else {
                matchExpression = new AviatorExpression();
            }
            matchExpression = ConditionExpressionDecorator.decorator(InsideExpressionDecorator.decorator(matchExpression));
            /*编译消息配置*/
            matchExpression.compileMsgConfig(config);
            /*编辑校验配置*/
            matchExpression.compile(config);
            return matchExpression;
        }

    }


}
